package com.g0dkar.leet.util.ognl;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;

import ognl.ObjectPropertyAccessor;
import ognl.OgnlException;

import com.g0dkar.leet.util.ognl.typeConversion.TypeConverter;
import com.g0dkar.leet.util.ognl.typeConversion.TypeConverterManager;
import com.g0dkar.leet.util.reflection.ReflectionUtils;

public class LeetOGNLObjectPropertyAccessor extends ObjectPropertyAccessor {
	public void setProperty(Map context, Object target, Object name, Object value) throws OgnlException {
		if (!ReflectionUtils.isPrimitive(value.getClass()) && ReflectionUtils.findField(name.toString(), value.getClass()) != null) {
			value = getConvertedValue(target, name.toString(), value);
		}
		
		super.setProperty(context, target, name, value);
	}
	
	public Object getConvertedValue(Object target, String name, Object value) throws OgnlException {
		Class<?> toType;
		Type[] rawGenericTypes;
		Type type = null;
		Class<?>[] genericTypes = null;
		ReflectionUtils.Field field = ReflectionUtils.getField(name, target.getClass());
		
		if (field != null) {
			type = field.genericType();
		}
		else {
			Field javaField = ReflectionUtils.findField(name, target.getClass());
			type = javaField.getGenericType();
		}
		
		if (type instanceof Class) {
			toType = (Class<?>) type;
			rawGenericTypes = null;
		}
		else {
			toType = (Class<?>) ((ParameterizedType) type).getRawType();
			rawGenericTypes = ((ParameterizedType) type).getActualTypeArguments();
		}
		
		if (rawGenericTypes != null) {
			genericTypes = new Class<?>[rawGenericTypes.length];
		
			for (int i = 0; i < rawGenericTypes.length; i++) {
				genericTypes[i] = (Class<?>) rawGenericTypes[i];
			}
		}
		
		TypeConverter typeConverter = TypeConverterManager.getConverterFor(toType);
		
		if (typeConverter != null) {
			try {
				value = typeConverter.fromString(value.toString(), toType, genericTypes);
			} catch (Exception e) {
				throw new OgnlException(name.toString(), e);
			}
		}
		
		return value;
	}
}
